home *** CD-ROM | disk | FTP | other *** search
/ Chip 2000 October / CHIP Turkiye Ekim 2000.iso / prog / naps / 04 / setup.exe / Gnucleus / GnuSock.cpp < prev    next >
C/C++ Source or Header  |  2000-07-15  |  28KB  |  1,277 lines

  1. /********************************************************************************
  2.  
  3.     Gnucleus - A node application for the Gnutella network
  4.     Copyright (C) 2000 John Marshall
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     For support, questions, comments, etc...
  20.     E-Mail: 
  21.         swabby@c0re.net
  22.     
  23.     Address:
  24.         21 Cadogan Way
  25.         Nashua, NH, USA 03062
  26.  
  27. ********************************************************************************/
  28.  
  29. // GnuSock.cpp : implementation file
  30. //
  31. #include "stdafx.h"
  32. #include "Packet.h"
  33. #include "Gnucleus.h"
  34. #include "GnucleusDoc.h"
  35.  
  36. #include "ViewSearch.h"
  37. #include "ViewSearchSpy.h"
  38. #include "ViewTransfer.h"
  39.  
  40. #include "GnuTransfer.h"
  41. #include "GnuHash.h"
  42. #include "GnuControl.h"
  43. #include "GnuSock.h"
  44.  
  45. #include "IPFilter.h"
  46.  
  47. #include <algorithm>
  48. #include <queue>
  49.  
  50. #include <process.h>
  51.  
  52. #ifdef _DEBUG
  53. #define new DEBUG_NEW
  54. #undef THIS_FILE
  55. static char THIS_FILE[] = __FILE__;
  56. #endif
  57.  
  58. /////////////////////////////////////////////////////////////////////////////
  59. // CGnuSock
  60.  
  61. CGnuSock::CGnuSock()
  62. {
  63.     Initialize ();
  64. }
  65.  
  66. CGnuSock::CGnuSock(CGnuControl *pGnuComm)
  67. {
  68.     Initialize ();
  69.  
  70.     GnuComm = pGnuComm;
  71.     
  72.     //LogFile = new CFile("C:\\Packet DEBUG.txt", CFile::modeCreate | CFile::modeWrite);
  73. }
  74.  
  75. void CGnuSock::Initialize ()
  76. {
  77.     GnuComm = NULL;
  78.  
  79.     next = NULL;
  80.  
  81.     Host = "";
  82.     Port = "";
  83.  
  84.     logPings = logPongs = logQueries =
  85.         logPushes = logQueryReplies = logUnknowns =
  86.         logGUID = logHops = logTTL = logPayload = logDropped = 0;
  87.  
  88.     Connected = 0;
  89.  
  90.     mExtraBytes = 0;
  91.     mExtraBytesStored = NULL;
  92.     m_dwNumOfBadPackets = 0;
  93.     m_dwNumOfRecivedPackets = 0;
  94.     m_dwNumOfSentPackets = 0;
  95.  
  96.     m_dwBytesIn = m_dwBytesOut = m_dwTotalBytesIn = m_dwTotalBytesOut
  97.         = m_dwByteAllottmentOut = m_dwByteAllottmentIn = m_iSizeOfPacketQueue = 0;
  98.  
  99.     m_timeLastHeardAT = CTime::GetCurrentTime();
  100.  
  101.     m_CanRelease = false;
  102.  
  103.     for(int i = 0; i < 8; i++)
  104.         RemoteHosts[i] = 0;
  105.  
  106. }
  107.  
  108. CGnuSock::~CGnuSock()
  109. {
  110.     delete [] mExtraBytesStored;
  111.     //delete GnuComm;
  112.     //delete next;
  113.  
  114.     // Clean out fifo queue
  115.     while(!m_PacketsOutQueue.empty())
  116.     {
  117.         delete m_PacketsOutQueue.front();
  118.         m_PacketsOutQueue.pop();
  119.     }
  120. }
  121.  
  122. // Do not edit the following lines, which are needed by ClassWizard.
  123. #if 0
  124. BEGIN_MESSAGE_MAP(CGnuSock, CAsyncSocket)
  125.     //{{AFX_MSG_MAP(CGnuSock)
  126.     //}}AFX_MSG_MAP
  127. END_MESSAGE_MAP()
  128. #endif    // 0
  129.  
  130. /////////////////////////////////////////////////////////////////////////////
  131. // CGnuSock member functions
  132.  
  133. // CAnsycSocket Overrides
  134.  
  135. void CGnuSock::OnConnect(int nErrorCode) 
  136. {
  137.     if (nErrorCode == 0)
  138.     {
  139.         Send("GNUTELLA CONNECT/0.4\n\n\0", 22);
  140.         GnuComm->BytesOut += 22;
  141.  
  142.         m_dwNumOfSentPackets++;
  143.         Log += "*** Connected to node, waiting for reply.\r\r\n";
  144.  
  145.         // Update the local host
  146.         UINT Trash;
  147.         GetSockName(GnuComm->localHost, Trash);
  148.     }
  149.  
  150.     CAsyncSocket::OnConnect(nErrorCode);
  151. }
  152.  
  153. void CGnuSock::OnReceive(int nErrorCode) 
  154. {
  155.     byte *pBuff = new byte[132000];
  156.     DWORD length = 0;
  157.     int iReceiveLength = 0, iErrorCode = 0;
  158.  
  159.     if (mExtraBytes)
  160.     {
  161.         ASSERT(mExtraBytesStored);
  162.         memcpy(pBuff, mExtraBytesStored, mExtraBytes);
  163.         length = mExtraBytes;
  164.     }
  165.  
  166.     iReceiveLength = Receive(&pBuff[length], 132000 - length);
  167.  
  168.     switch (iReceiveLength)
  169.     {
  170.     case 0:
  171.         // Connection has been closed, shutdown
  172.         WantToDisconnect();
  173.         m_CanRelease = true;
  174.         CleanUp();
  175.         break;
  176.  
  177.     case SOCKET_ERROR:
  178.         OutputDebugString("CGnuSock::OnReceive - SOCKET_ERROR\n");
  179.  
  180.         // received an error, see what it is and handle.
  181.         switch(GetLastError())
  182.         {
  183.             // fatal errors, need to disconnect
  184.         default:
  185.         case WSAECONNRESET:        // The virtual circuit was reset by the remote side.
  186.         case WSAENOTCONN:        // The socket is not connected.
  187.         case WSAENOTSOCK:        // The descriptor is not a socket.
  188.         case WSAESHUTDOWN:        // The socket has been shut down
  189.         case WSAECONNABORTED:    // The virtual circuit was aborted due to timeout or other failure.
  190.         case WSAEWOULDBLOCK:    //The socket is marked as nonblocking and the Receive operation would block.  Shouldn't happen.
  191.         case WSAENETDOWN:        // detected that the network subsystem failed
  192.  
  193.             WantToDisconnect();
  194.             m_CanRelease = true;
  195.             CleanUp();
  196.  
  197.             break;
  198.  
  199.             // non fatal errors, just handle individualy
  200.         case WSAEMSGSIZE:        // The datagram was too large to fit into the specified buffer and was truncated.
  201.                                 // Someone is probably sending us invalid packets, dump them.
  202.             WantToDisconnect();
  203.             m_CanRelease = true;
  204.             CleanUp();
  205.  
  206.             break;
  207.         }
  208.         return;
  209.         break;
  210.     default:        // just normal data
  211.         m_timeLastHeardAT = CTime::GetCurrentTime();
  212.         length += iReceiveLength;
  213.     }
  214.  
  215.     m_dwBytesIn += length - mExtraBytes;
  216.     GnuComm->BytesIn += length - mExtraBytes;
  217.  
  218.  
  219.     // We moved the previous extra data to the beginning
  220.     // of the current data burst, so release the temp storage.
  221.     mExtraBytes = 0;
  222.     delete [] mExtraBytesStored;
  223.     mExtraBytesStored = NULL;
  224.  
  225.     char *first = (char*) pBuff, *last = (char*) pBuff + length;
  226.     char *firstLineFeed = std::find (first, last, '\n');
  227.  
  228.     std::string firstLine;
  229.  
  230.     if (firstLineFeed != last)
  231.     {
  232.         firstLine.assign (first, firstLineFeed);
  233.     }
  234.  
  235.     // Check for a file request
  236.     if(!Connected)
  237.     {
  238.         if(firstLine.find( "GET /get/") != -1)
  239.         {
  240.             CString header(pBuff);
  241.             SOCKET sock = Detach ();
  242.             
  243.             WantToDisconnect();
  244.             m_CanRelease = true;
  245.             CleanUp();
  246.  
  247.             delete [] pBuff;
  248.  
  249.             ((CViewTransfer *) ((CGnucleusApp *) AfxGetApp())->TransferFrame->GetActiveView())->NewUpload(header, sock);
  250.  
  251.             return;
  252.         };
  253.     }
  254.  
  255.     // Check for PUSHes
  256.     if(!Connected)
  257.     {
  258.         std::string pushString ("GIV ");
  259.  
  260.         if (!firstLine.compare (0, pushString.size(), pushString))
  261.         {
  262.             // This is a PUSH response, not a normal client connection.  Give this to the control object
  263.             // and let it set up a transfer object to deal with it.
  264.  
  265.             SOCKET sock = Detach ();
  266.  
  267.             WantToDisconnect();
  268.             m_CanRelease = true;
  269.             CleanUp();
  270.  
  271.             delete [] pBuff;
  272.  
  273.             ((CViewTransfer *) ((CGnucleusApp *) AfxGetApp())->TransferFrame->GetActiveView())->NewPushDownload(firstLine, sock);
  274.  
  275.             return;
  276.         }
  277.     }
  278.     // Check for connection reply
  279.     if(!Connected)
  280.     {
  281.         if (!firstLine.compare ("GNUTELLA CONNECT/0.4"))
  282.             Send_ConnectOK();
  283.  
  284.         else if (!firstLine.compare ("GNUTELLA OK"))
  285.             Recieve_ConnectOK();
  286.  
  287.         // if not connected now, then disconnect
  288.         if(!Connected)
  289.         {
  290.             WantToDisconnect();
  291.             CleanUp();
  292.         }
  293.     }
  294.     if(Connected)
  295.     {
  296.         mExtraBytes = SplitBundle(pBuff, length);
  297.         if (0 != mExtraBytes)
  298.         {
  299.             // We shouldn't have almost a full 132000 byte
  300.             // buffer unprocessed!
  301.             ASSERT(130000 > mExtraBytes);
  302.             mExtraBytesStored = new byte[mExtraBytes];
  303.             memcpy(mExtraBytesStored, 
  304.                     &pBuff[length - mExtraBytes], mExtraBytes);
  305.         }
  306.     }
  307.  
  308.     delete [] pBuff;
  309.  
  310.     CAsyncSocket::OnReceive(nErrorCode);
  311. }
  312.  
  313. void CGnuSock::OnClose(int nErrorCode) 
  314. {
  315.     m_CanRelease = true;    // Socket has closed, definitely safe to release now
  316.  
  317.     // clean out the buffer
  318.     char * pBuf = new char[101];
  319.     int iRet = 0;
  320.     while( (iRet = Receive(pBuf, 100)) != 0 && iRet != SOCKET_ERROR );
  321.     delete [] pBuf;
  322.     
  323.     CleanUp();
  324.     GnuComm->RemoveNode(Host, Port);
  325.  
  326.     CAsyncSocket::OnClose(nErrorCode);
  327. }
  328.  
  329.  
  330. // Member Functions
  331. void CGnuSock::Recieve_ConnectOK()
  332. {
  333.     // Add Node to ListBox
  334.     if( SpaceAvailable() )
  335.     {
  336.         CString HostPort = Host;
  337.  
  338.         HostPort += ":";
  339.         HostPort += Port;
  340.  
  341.         GnuComm->Doc->QueueConnect.AddTail(HostPort);
  342.         GnuComm->Doc->Connections.AddTail(HostPort);
  343.  
  344.         Connected = 1;
  345.  
  346.         Log += "*** Reply from node recieved, connection established.\r\r\n";
  347.     }
  348. }
  349.  
  350. void CGnuSock::Send_ConnectOK()
  351. {
  352.     if( SpaceAvailable() )
  353.     {
  354.         Connected = 1;
  355.  
  356.         Send("GNUTELLA OK\n\n\0", 13); 
  357.         GnuComm->BytesOut += 13;
  358.  
  359.         // Add Node to ListBox
  360.         CString HostPort = Host;
  361.         HostPort += ":Inbound";
  362.  
  363.         GnuComm->Doc->QueueConnect.AddTail(HostPort);
  364.         GnuComm->Doc->Connections.AddTail(HostPort);
  365.  
  366.         Log += "*** Reply from node recieved, connection established.\r\r\n";
  367.         m_dwNumOfSentPackets++;
  368.     }
  369. }
  370.  
  371. bool CGnuSock::SpaceAvailable()
  372. {
  373.     if(GnuComm->Doc->m_DropForIncoming || GnuComm->Doc->m_MonitorType == 0)
  374.     {    
  375.         return 1;
  376.     }
  377.  
  378.     else if(GnuComm->Doc->m_MonitorType == 3 ||
  379.            (GnuComm->Doc->m_MonitorType == 2 && GnuComm->Doc->Connections.GetCount() < GnuComm->Doc->m_ConnectNum) ||
  380.            (GnuComm->Doc->m_MonitorType == 1 && GnuComm->Doc->Connections.GetCount() < GnuComm->Doc->m_ConnectNum - 1))
  381.     {
  382.         return 1;
  383.     }
  384.     else
  385.     {
  386.         WantToDisconnect();
  387.         m_CanRelease = true;
  388.         CleanUp();
  389.     }
  390.  
  391.     return 0;
  392. }
  393. //
  394. // MWD    05-12-2000    START
  395. // Here's the latest SplitBundle. It checks whether there's enough
  396. // data in the buffer at each decoding point to see whether it should
  397. // continue or process an error. If it detects an incomplete packet,
  398. // it returns to the caller the number of extra bytes so that it can
  399. // store them off for the next bundle.
  400. int CGnuSock::SplitBundle(byte *bundle, DWORD length)
  401. {
  402.     // Causing problems
  403.     //ASSERT(sizeof(packet_Header) <= length);
  404.  
  405.     DWORD Payload;
  406.     DWORD nextPos = 0;
  407.  
  408.     packet_Header *packet;
  409.  
  410.     enum status 
  411.     { 
  412.         status_DONE, 
  413.         status_CONTINUE, 
  414.         status_BAD_PACKET, 
  415.         status_INCOMPLETE_PACKET 
  416.     };
  417.     status theStatus = status_CONTINUE;
  418.  
  419.     do
  420.     {
  421.         if ((nextPos + sizeof(packet_Header)) > length)
  422.             theStatus = status_INCOMPLETE_PACKET;
  423.         else
  424.         {
  425.             packet = (packet_Header *) (bundle + nextPos);
  426.             Payload = makeD( flipX( packet->Payload ) ); 
  427.          
  428.             if((packet->Function == 0x00 && Payload ==  0) ||
  429.                (packet->Function == 0x01 && Payload == 14) ||
  430.                (packet->Function == 0x40 && Payload == 26) ||
  431.                (packet->Function == 0x80 && Payload >=  2 && Payload <= 257) ||
  432.                (packet->Function == 0x81 && Payload >= 27 && Payload <= 67075))
  433.             {
  434.                 if ((nextPos + sizeof(packet_Header) + Payload) <= length)
  435.                 {
  436.                     HandlePacket(packet, 23 + Payload);
  437.                     nextPos += 23 + Payload;
  438.                     if (nextPos == length)
  439.                         theStatus = status_DONE;
  440.                 }
  441.                 else
  442.                     theStatus = status_INCOMPLETE_PACKET;
  443.             }
  444.             else
  445.             {
  446. /* DW
  447.                 theStatus = status_BAD_PACKET;
  448.  
  449.                 // If we had a bad packet, just throw it all out.
  450.                 nextPos = length;
  451.                 
  452.                 m_dwNumOfBadPackets++;
  453. */
  454.                 // !!** DW - Dean Wyant 6/19/00 
  455.                 // The above losses all pending messages in the buffer
  456.                 // Let's just find the next possible header
  457.                 theStatus = status_CONTINUE;
  458.  
  459.                 if (nextPos < (length - sizeof(packet_Header)))
  460.                 {
  461.                   nextPos++;
  462.                   length--;
  463.                 }
  464.                 else
  465.                 { // No good header found - but leave the , header bytes data for next time
  466.                           theStatus = status_BAD_PACKET;
  467.                   m_dwNumOfBadPackets++;
  468.                 }
  469.             }
  470.         }
  471.     } while (status_CONTINUE == theStatus);
  472.  
  473.     if (logUnknowns)
  474.     {
  475.         switch (theStatus)
  476.         {
  477.             case status_DONE:
  478.                 break;
  479.             case status_BAD_PACKET:
  480.                 Log += "Bad packet\r\r\n";
  481.                 break;
  482.             case status_INCOMPLETE_PACKET:
  483.                 {
  484.                     //Log += "Extra ";
  485.                     //char buffer[20];
  486.                     //itoa(length - nextPos, buffer, 10);
  487.                     //Log += buffer;
  488.                     //Log += " Remaining\r\r\n";
  489.                 }
  490.                 break;
  491.             case status_CONTINUE:
  492.                 // This should never happen.
  493.                 ASSERT(FALSE);
  494.                 break;
  495.             default:
  496.                 break;
  497.         }
  498.     }
  499.  
  500.     return length - nextPos;
  501. }
  502. // MWD    05-12-2000    END
  503. //
  504.  
  505. void CGnuSock::HandlePacket(packet_Header *packet, int length)
  506. {
  507.     switch(packet->Function)
  508.     {
  509.     case 0x00:
  510.         Recieve_Ping((packet_Ping *) packet, length);
  511.         m_dwNumOfRecivedPackets++;
  512.         GnuComm->totalPings++;
  513.         break;
  514.  
  515.     case 0x01:
  516.         Recieve_Pong((packet_Pong *) packet, length);
  517.         m_dwNumOfRecivedPackets++;
  518.         GnuComm->totalPongs++;
  519.         break;
  520.  
  521.     case 0x40:
  522.         Recieve_Push((packet_Push *) packet, length);
  523.         m_dwNumOfRecivedPackets++;
  524.         GnuComm->totalPushes++;
  525.         break;
  526.  
  527.     case 0x80:
  528.         Recieve_Query((packet_Query *) packet, length);
  529.         m_dwNumOfRecivedPackets++;
  530.         GnuComm->totalQueries++;
  531.         break;
  532.  
  533.     case 0x81:
  534.         Recieve_QueryReply((packet_QueryReply *) packet, length);
  535.         m_dwNumOfRecivedPackets++;
  536.         GnuComm->totalQueryReplies++;
  537.         break;
  538.  
  539.     default:
  540.         // Disable unknowns
  541.         Recieve_Unknown((byte *) packet, length);
  542.         m_dwNumOfBadPackets++;
  543.         GnuComm->totalUnknowns++;
  544.         break;
  545.     }
  546. }
  547.  
  548. bool CGnuSock::InspectPacket(packet_Header *packet, int length)
  549. {
  550.     // Increment hops of packet first thing
  551.     packet->Hops++; 
  552.  
  553.     // Add data to the statistic values
  554.     if(packet->Hops > 7)
  555.         GnuComm->totalHopsBig++;
  556.     else
  557.         GnuComm->totalHops++;
  558.  
  559.     if(packet->TTL > 7)
  560.         GnuComm->totalTTLsBig++;
  561.     else
  562.         GnuComm->totalTTLs++;
  563.  
  564.  
  565.     // If packet has hopped more than 7 times kill it
  566.     if(packet->Hops > 7)  
  567.         return 0;    
  568.  
  569.     // Reset TTL of packet if it needs to be
  570.     if(packet->TTL > 7)
  571.         packet->TTL = 7 - packet->Hops;
  572.  
  573.     return 1;
  574. }
  575.  
  576. void CGnuSock::Recieve_Ping(packet_Ping *Ping, int length)
  577. {
  578.     if(logPings)
  579.         Log += "Ping";
  580.  
  581.     if(!InspectPacket((packet_Header *) Ping, length))
  582.     {
  583.         if(logPings)
  584.             Log += ", dropped (hops expired)\r\r\n";
  585.  
  586.         return;
  587.     }
  588.     
  589.     if(Ping->Header.TTL == 0) // Check its TTL and pass it along
  590.     {
  591.         if(logPings)
  592.             Log += ", dropped (TTL expired)\r\r\n";
  593.  
  594.         return;
  595.     }
  596.     else
  597.         Ping->Header.TTL--;
  598.  
  599.     // Check the GUID of the packet to make sure no duplicates
  600.     CGnuControl::GuidHash::iterator it = GnuComm->m_cache.find (Ping->Header.Guid);
  601. //    key_data *key = GnuComm->HashTable.FindValue(&Ping->Header.Guid);
  602.     
  603. //    if(key == NULL)
  604.     if (it == GnuComm->m_cache.end ())
  605.     {
  606. //        GnuComm->HashTable.Insert(&Ping->Header.Guid, this);
  607.         GnuComm->m_cache[Ping->Header.Guid] = this;
  608.         GnuComm->Broadcast_Ping(Ping, length, this);
  609.         Send_Pong(Ping->Header.Guid, Ping->Header.Hops);
  610.     }
  611.     else
  612.     {
  613.         if((*it).second == this)
  614.         {
  615.             if(logPings)
  616.                 Log += ", dropped (duplicate)\r\r\n";
  617.  
  618.             return;
  619.         }
  620.         else
  621.         {
  622.             if(logPings)
  623.                 Log += ", dropped (routing)\r\r\n";
  624.  
  625.             return;
  626.         }
  627.     }
  628.  
  629.     if(logPings)
  630.         Log += "\r\r\n";
  631. }
  632.  
  633. void CGnuSock::Recieve_Pong(packet_Pong *Pong, int length)
  634. {
  635.     if(logPongs)
  636.         Log += "Pong";
  637.  
  638.     if(!InspectPacket((packet_Header *) Pong, length))
  639.     {
  640.         if(logPongs)
  641.             Log += ", dropped (hops expired)\r\r\n";
  642.  
  643.         return;
  644.     }
  645.     
  646.     if(Pong->Host.a == 0 && Pong->Host.b == 0 && Pong->Host.c == 0 && Pong->Host.d == 0)
  647.     {
  648.         if(logPongs)
  649.             Log += ", dropped (TTL expired)\r\r\n";
  650.  
  651.         return;
  652.     }
  653.  
  654.     // Check its TTL and pass it along
  655.     if(Pong->Header.TTL == 0)
  656.     {
  657.         if(logPongs)
  658.             Log += ", dropped (TTL expired)\r\r\n";
  659.  
  660.         return;
  661.     }
  662.     else
  663.         Pong->Header.TTL--;
  664.  
  665.     // Add pong to host cache
  666.     CString HostPort = IPtoStr(Pong->Host);
  667.             HostPort += ":";
  668.             HostPort += WrdtoStr(Pong->Port);
  669.  
  670.     if ((0 != Pong->Port) && 
  671.             CIPFilter::AllowIP(Pong->Host) &&
  672.             CIPFilter::IsPrivateIP(Pong->Host, Pong->Host) == 0)
  673.     {
  674.         GnuComm->Doc->AddToQueueCache(HostPort);
  675.     }
  676.  
  677. /*
  678.     while(GnuComm->Doc->QueueCache.GetCount() > 500)
  679.         GnuComm->Doc->QueueCache.RemoveTail();
  680.  
  681.     if(Pong->Port != 0)
  682.     {
  683.         // Don't add duplicate hosts
  684.         if (!GnuComm->Doc->QueueCache.Find (HostPort))
  685.         {
  686.             if (CIPFilter::AllowIP (Pong->Host.a, Pong->Host.b, Pong->Host.c, Pong->Host.d))
  687.             {
  688.                 GnuComm->Doc->QueueCache.AddTail( HostPort);
  689.             }
  690.         }
  691.     }
  692. */
  693.  
  694.     // Check the GUID of the packet to make sure no duplicates
  695.     CGnuControl::GuidHash::iterator it = GnuComm->m_cache.find (Pong->Header.Guid);
  696.     key_data *sendKey = GnuComm->SendTable.FindValue(&Pong->Header.Guid);
  697.  
  698.     if(sendKey != NULL)
  699.     {
  700.         if(logPongs)
  701.             Log += " recieved\r\r\n";
  702.  
  703.         RemoteHosts[Pong->Header.Hops]++;
  704.  
  705.         return;
  706.     }
  707.  
  708.     if(it != GnuComm->m_cache.end ())
  709.     {
  710.         key_data key;
  711.  
  712.         key.Guid = Pong->Header.Guid;
  713.         key.Origin = (*it).second;
  714.         GnuComm->Route_Pong(Pong, length, &key);
  715.     }
  716.     else
  717.     {
  718.         if(logPongs)
  719.             Log += ", dropped (routing)\r\r\n";
  720.  
  721.         return;
  722.     }  
  723.  
  724.     if(logPongs)
  725.         Log += "\r\r\n";
  726. }
  727.  
  728. void CGnuSock::Recieve_Push(packet_Push *Push, int length)
  729. {
  730.     if(logPushes)
  731.         Log += "Push";
  732.  
  733.     if(!InspectPacket((packet_Header *) Push, length))
  734.     {
  735.         if(logPushes)
  736.             Log += ", dropped (hops expired)\r\r\n";
  737.  
  738.         return;
  739.     }
  740.  
  741.     // After thinking about this its probably not the best to censor other people's push requests
  742.     /*if (!CIPFilter::AllowIP (Push->Host.a, Push->Host.b, Push->Host.c, Push->Host.d))
  743.     {
  744.         if(logPushes)
  745.             Log += ", dropped (IP filter)\r\r\n";
  746.  
  747.         return;
  748.     }*/
  749.  
  750.     if(Push->Host.a == 0 && Push->Host.b == 0 && Push->Host.c == 0 && Push->Host.d == 0)
  751.     {
  752.         if(logPushes)
  753.             Log += ", dropped (null host)\r\r\n";
  754.  
  755.         return;
  756.     }
  757.  
  758.     // Check its TTL and pass it along
  759.     if(Push->Header.TTL == 0)
  760.     {
  761.         if(logPushes)
  762.             Log += ", dropped (TTL expired)\r\r\n";
  763.  
  764.         return;
  765.     }
  766.     else
  767.         Push->Header.TTL--;
  768.  
  769.     // Check to see if the push is for us
  770.     if(GnuComm->ClientGUID == Push->ClientID)
  771.     {
  772.         if(logPushes)
  773.             Log += " received\r\r\n";
  774.  
  775.         QueryItem File;
  776.         File.Handle = 16000;
  777.         File.Index  = makeD( flipX(Push->Index) );
  778.         File.Guid   = Push->ClientID;
  779.         File.Host   = Push->Host;
  780.         File.Port   = Push->Port;
  781.         File.Status = "Push";
  782.         File.TransferType = 'U';
  783.  
  784.         GnuComm->AddTransfer(File);
  785.         GnuComm->GetTransfer(16000, 'U')->Connect( IPtoStr(File.Host), File.Port);
  786.  
  787.         return;
  788.     }
  789.  
  790.     // Check the GUID of the packet to make sure no duplicates
  791.     key_data *key = GnuComm->HashClientTable.FindValue(&Push->ClientID);
  792.     
  793.     if(key != NULL)
  794.         GnuComm->Route_Push(Push, length, key);
  795.     else
  796.     {
  797.         if(logPushes)
  798.             Log += ", dropped (routing)\r\r\n";
  799.  
  800.         return;
  801.     }  
  802.  
  803.     if(logPushes)
  804.         Log += "\r\r\n";
  805. }
  806.  
  807. void CGnuSock::Recieve_Query(packet_Query *Query, int length)
  808. {
  809.     if(logQueries)
  810.         Log += "Query";
  811.  
  812.     if(!InspectPacket((packet_Header *) Query, length))
  813.     {
  814.         if(logQueries)
  815.             Log += ", dropped (hops expired)\r\r\n";
  816.  
  817.         return;
  818.     }
  819.  
  820.     // Check its TTL and pass it along
  821.     if(Query->Header.TTL == 0)
  822.     {
  823.         if(logQueries)
  824.             Log += ", dropped (TTL expired)\r\r\n";
  825.  
  826.         return;
  827.     }
  828.     else
  829.         Query->Header.TTL--;
  830.  
  831.     // Check the GUID of the packet to make sure no duplicates
  832.     CGnuControl::GuidHash::iterator it = GnuComm->m_cache.find (Query->Header.Guid);
  833.     
  834.     if(it == GnuComm->m_cache.end ())
  835.     {
  836.         GnuComm->m_cache[Query->Header.Guid] = this;
  837.         GnuComm->Broadcast_Query(Query, length, this);
  838.     }
  839.     else
  840.         if((*it).second == this)
  841.         {
  842.             if(logQueries)
  843.                 Log += ", dropped (duplicate)\r\r\n";
  844.  
  845.             return;
  846.         }
  847.         else
  848.         {
  849.             if(logQueries)
  850.                 Log += ", dropped (routing)\r\r\n";
  851.  
  852.             return;
  853.         }
  854.  
  855.     // Extract the query
  856.     BYTE *RawQuery = (BYTE *) Query;
  857.  
  858.     CString SearchString;
  859.  
  860.     int i = 25;
  861.     while(i < 23 + makeD(flipX(Query->Header.Payload)) && RawQuery[i] != '\0')
  862.         SearchString += RawQuery[i++];
  863.     
  864.     if(logQueries)
  865.         Log += "\r\r\n";
  866.     
  867.     //
  868.     // Log search request to spy window.
  869.     //
  870.     GnuComm->Doc->UpdateSpy( SearchString );
  871.     
  872.     CurrentOrigin = Query->Header.Guid;
  873.     CurrentSearch = SearchString;
  874.     GnuComm->PushQueryToQueue(this);
  875.  
  876.     //Log += "\r\r\n";
  877. }
  878.  
  879. void CGnuSock::Recieve_QueryReply(packet_QueryReply *QueryReply, DWORD length)
  880. {
  881.     if(logQueryReplies)
  882.         Log += "Query Hit";
  883.  
  884.     // Out of order, but this bandaid gets search results only for us
  885.     // If the query result is coming from more than 7 hops away
  886.     key_data *sendKey = GnuComm->SendTable.FindValue(&QueryReply->Header.Guid);
  887.     
  888.     byte *pReply = (byte *) QueryReply;
  889.     GUID *pClientID  = (GUID *) &pReply[length - 16];
  890.  
  891.     if(sendKey != NULL)
  892.     {
  893.         if ( CIPFilter::AllowIP( QueryReply->Host ) )        // test against search filter
  894.         {
  895.             if(logQueryReplies)
  896.                 Log += " recieved\r\r\n";
  897.  
  898.             GnuComm->Doc->UpdateSearchViews(QueryReply);
  899.  
  900.             GnuComm->HashClientTable.Insert(pClientID, this);
  901.  
  902.             return;
  903.         }
  904.         else
  905.         {
  906.             if(logQueryReplies)
  907.                 Log += " dropped (filtered)\r\r\n";
  908.             
  909.             return;
  910.             
  911.         }
  912.     }
  913.  
  914.     // Now go along and inspect it
  915.     if(!InspectPacket((packet_Header *) QueryReply, length))
  916.     {
  917.         if(logQueryReplies)
  918.             Log += ", dropped (hops expired)\r\r\n";
  919.  
  920.         return;
  921.     }
  922.  
  923.     if(QueryReply->Host.a == 0 && QueryReply->Host.b == 0 && QueryReply->Host.c == 0 && QueryReply->Host.d == 0)
  924.     {
  925.         if(logQueryReplies)
  926.             Log += ", dropped (null host)\r\r\n";
  927.  
  928.         return;
  929.     }
  930.  
  931.     if(QueryReply->TotalHits == 0)
  932.     {
  933.         if(logQueryReplies)
  934.             Log += ", dropped (nothing found)\r\r\n";
  935.  
  936.         return;
  937.     }
  938.  
  939.     // Check its TTL and pass it along
  940.     if(QueryReply->Header.TTL == 0)
  941.     {
  942.         if(logQueryReplies)
  943.             Log += ", dropped (TTL expired)\r\r\n";
  944.  
  945.         return;
  946.     }
  947.     else
  948.         QueryReply->Header.TTL--;
  949.  
  950.  
  951.     // Check the GUID of the packet to make sure no duplicates
  952.     CGnuControl::GuidHash::iterator it2 = GnuComm->m_cache.find (QueryReply->Header.Guid);
  953.         //    key_data* key = GnuComm->HashTable.FindValue(&QueryReply->Header.Guid);
  954.     
  955.     if(it2 != GnuComm->m_cache.end ())
  956.     {
  957.         key_data key;
  958.         key.Guid = (*it2).first;
  959.         key.Origin = (*it2).second;
  960.         GnuComm->Route_QueryReply(QueryReply, length, &key);
  961.     }
  962.     else
  963.     {
  964.         if(logQueryReplies)
  965.             Log += ", dropped (routing)\r\r\n";
  966.  
  967.         return;
  968.     }
  969.  
  970.     if(logQueryReplies)
  971.         Log += "\r\r\n";
  972. }
  973.  
  974. void CGnuSock::Recieve_Unknown(byte *pBuff, int length)
  975. {
  976.     if(logUnknowns)
  977.         Log += "Unknown, dropped";
  978.  
  979.     if(!InspectPacket((packet_Header *) pBuff, length))
  980.         return;
  981.  
  982.     if(logUnknowns)
  983.         Log += ",\r\r\n";
  984. }
  985.  
  986. void CGnuSock::Send_Ping()
  987. {
  988.     GUID Guid = GUID_NULL;
  989.     ::CoCreateGuid(&Guid);
  990.     if (Guid == GUID_NULL)
  991.     {
  992.         AfxMessageBox("Failed to create a GUID to send.");
  993.         return;
  994.     }
  995.  
  996.     packet_Ping Ping;
  997.     
  998.     Ping.Header.Guid = Guid;
  999.     Ping.Header.Function = 0;
  1000.     Ping.Header.Hops = 0;
  1001.     Ping.Header.TTL = 7;
  1002.     Ping.Header.Payload = flipX( makeX(0) );
  1003.  
  1004.     GnuComm->m_cache[Guid] = NULL;
  1005.     GnuComm->SendTable.Insert(&Guid, NULL);
  1006.     Send(&Ping, 23);
  1007.  
  1008.     GnuComm->BytesOut += 23;
  1009.     m_dwNumOfSentPackets++;
  1010. }
  1011.  
  1012. void CGnuSock::Send_Pong(GUID Guid, int Hops)
  1013. // Send init responses out the same socket from which they came
  1014. {
  1015.     // Get the local address of this machine
  1016.     DWORD localPort = GnuComm->localPort;
  1017.  
  1018.     IP Host;
  1019.     if( IPtoStr(GnuComm->Doc->m_ForceIP) != "0.0.0.0")
  1020.         Host = GnuComm->Doc->m_ForceIP;
  1021.     else
  1022.         Host = StrtoIP(GnuComm->localHost);
  1023.  
  1024.     // Get the current file count and total size
  1025.     DWORD FileCount = 0;
  1026.     DWORD FileSize = 0;
  1027.  
  1028.     std::vector<DWORD>::iterator itCount;
  1029.     std::vector<DWORD>::iterator itSize;
  1030.  
  1031.     for(itCount = GnuComm->Doc->SharedDirCount.begin(), itSize = GnuComm->Doc->SharedDirSize.begin();
  1032.         itCount != GnuComm->Doc->SharedDirCount.end(), itSize != GnuComm->Doc->SharedDirSize.end();
  1033.         itCount++, itSize++)
  1034.     {
  1035.         FileCount += *itCount;
  1036.         FileSize  += *itSize;
  1037.     }
  1038.  
  1039.     // Build the packet
  1040.     packet_Pong *Pong = new packet_Pong;
  1041.  
  1042.     Pong->Header.Guid        = Guid;
  1043.     Pong->Header.Function    = 0x01;
  1044.     Pong->Header.TTL        = Hops;
  1045.     Pong->Header.Hops        = 0;
  1046.     Pong->Header.Payload    = flipX( makeX(14) );
  1047.  
  1048.     Pong->Port                = (WORD) localPort;
  1049.     Pong->Host                = Host;
  1050.     Pong->FileCount            = flipX( makeX(FileCount) );
  1051.     Pong->FileSize            = flipX( makeX(FileSize) );
  1052.  
  1053.     Send(Pong, 37);
  1054.     GnuComm->BytesOut += 37;
  1055.  
  1056.     m_dwNumOfSentPackets++;
  1057.  
  1058.     delete Pong;
  1059. }
  1060.  
  1061. void CGnuSock::Send_Query(CViewSearch *pSearch)
  1062. {
  1063.     BYTE QueryByte[23 + 255];
  1064.     packet_Query Query;
  1065.     byte *pQuery = (byte *) &Query;
  1066.  
  1067.      Query.Header.Guid = pSearch->myGuid;
  1068.     Query.Header.Function = 0x80;
  1069.     Query.Header.Hops = 0;
  1070.     Query.Header.TTL = 7;
  1071.     Query.Header.Payload = flipX( makeX(pSearch->length + 3) );
  1072.     Query.Speed = pSearch->BytesPerSec;
  1073.  
  1074.     for(int i = 0; i < 25; i++)
  1075.         QueryByte[i] = pQuery[i];
  1076.  
  1077.     // Add Search
  1078.     for(i = 0; i < pSearch->keyword.GetLength(); i++)
  1079.         QueryByte[25 + i] = pSearch->keyword.GetAt(i); 
  1080.  
  1081.     QueryByte[25 + pSearch->length] = NULL;
  1082.  
  1083.     // Send the query
  1084.     Send(QueryByte, 26 + pSearch->length);
  1085.     GnuComm->BytesOut += 26 + pSearch->length;
  1086.  
  1087.     m_dwNumOfSentPackets++;
  1088. }
  1089.  
  1090. void CGnuSock::CleanUp()
  1091. {
  1092.     POSITION pos;
  1093.     CString HostPort = Host;
  1094.  
  1095.     Log += "*** Connection with node closed.\r\r\n";
  1096.  
  1097.     HostPort += ":";
  1098.     HostPort += Port;
  1099.  
  1100.     pos = GnuComm->Doc->Connections.Find(HostPort);
  1101.  
  1102.     if(pos != NULL)
  1103.     {
  1104.         GnuComm->Doc->Connections.RemoveAt(pos);
  1105.  
  1106.         GnuComm->Doc->QueueDisconnect.AddTail(HostPort);
  1107.     }
  1108.  
  1109.     Connected = 0;
  1110. }
  1111.  
  1112. void CGnuSock::RefreshHostCount()
  1113. {
  1114.     for(int i = 0; i < 8; i++)
  1115.         RemoteHosts[i] = 0;
  1116.  
  1117.     Send_Ping();
  1118. }
  1119.  
  1120. DWORD CGnuSock::TotalRemoteHosts()
  1121. {        
  1122.     DWORD Total = 0;
  1123.  
  1124.     for(int i = 0; i < 8; i++)
  1125.         Total += RemoteHosts[i];
  1126.  
  1127.     return Total;
  1128. }
  1129.  
  1130. void CGnuSock::WantToDisconnect()
  1131. {
  1132.     // Let spock know that he is going to die, so it might as well
  1133.     // speed up the process.
  1134.  
  1135.     if(m_hSocket != INVALID_SOCKET)
  1136.     {
  1137.         AsyncSelect(FD_CLOSE);
  1138.         ShutDown(sends);
  1139.     }
  1140.  
  1141.     Connected = false;
  1142. }
  1143.  
  1144. ////////////////////////////////////////////////////////////
  1145. // author: Nathan Brown
  1146. //
  1147. // Called from CGnuControl::QueriesSearchThread to send results
  1148. void CGnuSock::SendFileResults(std::queue <QueryResult> & resultQueue, GUID & Origin)
  1149. {
  1150.     try            // socket may have died
  1151.     {
  1152.         CGnucleusDoc *Doc = GnuComm->Doc;
  1153.         int hits = resultQueue.size();
  1154.  
  1155.         WORD localPort = GnuComm->localPort;
  1156.  
  1157.         IP Host;
  1158.         if( IPtoStr(Doc->m_ForceIP) != "0.0.0.0")
  1159.             Host = Doc->m_ForceIP;
  1160.         else
  1161.             Host = StrtoIP(GnuComm->localHost);
  1162.  
  1163.         DWORD Speed;
  1164.         if(Doc->m_ConnectSpeed)
  1165.             Speed = Doc->m_ConnectSpeed;
  1166.         else
  1167.             Speed = Doc->m_EstSpeed;
  1168.  
  1169.         BYTE *packet = new BYTE[67075];
  1170.         packet_QueryReply *Reply = (packet_QueryReply *) packet;
  1171.  
  1172.         Reply->Header.Guid = Origin;
  1173.         Reply->Header.Function = 0x81;
  1174.         Reply->Header.TTL = 7;
  1175.         Reply->Header.Hops = 0;
  1176.         //Reply->Header.Payload = flipX( makeX(length - 23) );
  1177.  
  1178.         Reply->TotalHits = hits;
  1179.         Reply->Port = localPort;
  1180.         Reply->Host = Host;
  1181.         Reply->Speed = flipX( makeX(Speed));
  1182.  
  1183.         DWORD pos = 34;
  1184.  
  1185.         while (!resultQueue.empty ())
  1186.         {
  1187.             const QueryResult& tmpReply = resultQueue.front ();    // Gives us a reference to the top of the queue
  1188.  
  1189.             DWORD dwSize = tmpReply.GetSize ();
  1190.  
  1191.             tmpReply.CopyToBuffer (packet + pos, dwSize);
  1192.  
  1193.             pos += dwSize;
  1194.  
  1195.             resultQueue.pop ();
  1196.         }
  1197.  
  1198.         GUID Guid = GnuComm->ClientGUID;
  1199.  
  1200.         ::memcpy (packet + pos, &Guid, sizeof (Guid));
  1201.  
  1202.         // Set the payload
  1203.         Reply->Header.Payload = flipX( makeX(pos - 7));
  1204.  
  1205.         Send(packet, pos + 16);
  1206.  
  1207.         GnuComm->BytesOut += (pos + 16);
  1208.  
  1209.         m_dwNumOfSentPackets++;
  1210.  
  1211.         delete [] packet;
  1212.     }
  1213.     catch( ... )
  1214.     {
  1215.         return;
  1216.     }
  1217. }
  1218.  
  1219. //: Override to Limit outgoing packets
  1220. int CGnuSock::Send( const void* lpBuf, int nBufLen, int nFlags )
  1221. {
  1222.     int i_return;
  1223.  
  1224.     if(m_dwByteAllottmentOut)
  1225.     {
  1226.         // save the buffer
  1227.         void * lp_save_buff = new BYTE[nBufLen];
  1228.         memcpy(lp_save_buff, lpBuf, nBufLen);
  1229.  
  1230.         m_CritSecPacketQueue.Lock();                // only one thread can access this queue at once.
  1231.         m_PacketsOutQueue.push(lp_save_buff);
  1232.         m_PacketsOutQueueSize.push(nBufLen);
  1233.         m_CritSecPacketQueue.Unlock();
  1234.     }
  1235.     else        // just send like normal
  1236.     {
  1237.         CAsyncSocket::Send(lpBuf, nBufLen, nFlags);
  1238.  
  1239.         m_dwBytesOut += nBufLen;
  1240.     }
  1241.  
  1242.     ProccessPacketQueue();
  1243.  
  1244.     i_return = m_dwByteAllottmentOut - m_dwBytesOut;
  1245.     i_return = i_return > 0 ? i_return : 1;        // should be at least 1 if no problems
  1246.  
  1247.     return i_return;
  1248. }
  1249.  
  1250. int CGnuSock::ProccessPacketQueue()
  1251. {
  1252.     int n_buf_len = 0;
  1253.     void * lp_buff = NULL;
  1254.  
  1255.     m_CritSecPacketQueue.Lock();
  1256.  
  1257.     while( (m_dwBytesOut < m_dwByteAllottmentOut || !m_dwByteAllottmentOut) 
  1258.         && !m_PacketsOutQueue.empty())
  1259.     {
  1260.         lp_buff = m_PacketsOutQueue.front();
  1261.         m_PacketsOutQueue.pop();
  1262.         n_buf_len = m_PacketsOutQueueSize.front();
  1263.         m_PacketsOutQueueSize.pop();
  1264.  
  1265.         CAsyncSocket::Send(lp_buff, n_buf_len);
  1266.         m_dwBytesOut += n_buf_len;
  1267.  
  1268.         delete lp_buff;
  1269.  
  1270.     }
  1271.  
  1272.     m_CritSecPacketQueue.Unlock();
  1273.  
  1274.     m_iSizeOfPacketQueue = m_PacketsOutQueue.size();
  1275.     // return weather empty or not.
  1276.     return m_iSizeOfPacketQueue;
  1277. }